﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DeVetma.admin.classes;
using DeVetma.admin.models.database.metadata;
using DeVetma.admin.models.database;
using DeVetma.admin.models.entities;

namespace DeVetma.admin.models.managers
{
    public class SettingsManager : DataManager<Setting>
    {
        public override bool add(Setting entity)
        {
            Setting test = getByTypeName(entity.type, entity.name);
            if (test != null)
            {
                entity.id = test.id;
                return update(entity);
            }

            return base.add(entity);
        }

        public override bool addAll(Setting[] entities, List<Setting> failed)
        {
            bool hasFailure = false;

            foreach (var entity in entities)
            {
                Setting test = getByTypeName(entity.type, entity.name);
                if (test != null)
                {
                    entity.id = test.id;
                    if (!update(entity))
                    {
                        hasFailure = true;
                        if (failed != null)
                            failed.Add(entity);
                    }

                    continue;
                }

                if (!Database.instance().addEntity(entity))
                {
                    hasFailure = true;
                    if (failed != null)
                        failed.Add(entity);
                }
            }

            return !hasFailure;
        }

        public override string ensureKey(Setting entity)
        {
            List<Setting> settings = getAll();

            int len = (settings.Count < 1 ? 1 : ((int)Math.Log10(settings.Count)) + 2);
            entity.id = Utilities.randomizeNumericString(len);
            while (settings.Exists(q => q.id == entity.id))
                entity.id = Utilities.randomizeNumericString(len);

            return entity.id;
        }

        public bool hasByType(string type)
        {
            return getByType(type).Count > 0;
        }

        public bool hasByTypeName(string type, string name)
        {
            return getByTypeName(type, name) != null;
        }

        public List<Setting> getByType(string type)
        {
            return getAll().Where(q => q.type == type).ensure();
        }

        public Setting getByTypeName(string type, string name)
        {
            if (getByType(type).Count(q => q.name == name) != 1)
                return null;

            return getByType(type).SingleOrDefault(q => q.name == name);
        }

        public string getRawValueByTypeName(string type, string name)
        {
            return getByTypeName(type, name)._value;
        }

        public string[] getRawValuesByType(string type)
        {
            List<Setting> settings = getByType(type);
            List<string> toReturn = new List<string>();

            foreach (var setting in settings)
                toReturn.Add(setting._value);

            return toReturn.ToArray();
        }

        public T getValueByTypeName<T>(string type, string name)
        {
            return getByTypeName(type, name).value<T>();
        }

        public T[] getValuesByType<T>(string type)
        {
            List<Setting> settings = getByType(type);
            List<T> toReturn = new List<T>();

            foreach (var setting in settings)
                toReturn.Add(setting.value<T>());

            return toReturn.ToArray();
        }

        public string[] getAllClothesColors()
        {
            return getValuesByType<string>("Clothes.Colors");
        }

        public string[] getAllClothesMaterials()
        {
            return getValuesByType<string>("Clothes.Materials");
        }

        public string setValue(string type, string name, object value)
        {
            Setting setting = getByTypeName(type, name);

            if (setting == null)
            {
                setting = new Setting
                {
                    name = name,
                    type = type,
                    _value = value.ToString()
                };

                setting = add(setting) ? setting : null;
            }

            return setting != null ? setting.id : null;
        }

        public bool deleteByTypeName(string type, string name)
        {
            Setting test = getByTypeName(type, name);

            return test != null ? delete(test) : false;
        }

        public bool deleteAllByType(string type)
        {
            return deleteAll(getByType(type).ToArray(), null);
        }

        public bool addColor(string color)
        {
            return setValue("Clothes.Colors", color, color) != null;
        }

        public bool deleteColor(string color)
        {
            return deleteByTypeName("Clothes.Colors", color);
        }

        public bool addMaterial(string material)
        {
            return setValue("Clothes.Materials", material, material) != null;
        }

        public bool deleteMaterial(string material)
        {
            return deleteByTypeName("Clothes.Materials", material);
        }
    }
}